Skip to content

Add cross-host workspace lease for mutating Workbench runs - #99

Merged
VeryComplexAndLongName merged 2 commits into
mainfrom
feat/cross-host-workspace-lease
Aug 28, 2026
Merged

VeryComplexAndLongName merged 2 commits into
mainfrom
feat/cross-host-workspace-lease

Conversation

@VeryComplexAndLongName

Copy link
Copy Markdown
Owner

Summary

  • Adds ADR 0010 and a versioned, file-based cross-host workspace lease so at most one host process (VS Code extension or standalone server) can run a mutating Workbench operation on a given workspace at a time. A blocked host gets an immediate, actionable error naming the current holder; a stale (crashed) holder's lease is reclaimed and disclosed.
  • Fixes wire.ts's COMMAND_KINDS duplicating core's CommandKind list.
  • Scope expansion found mid-implementation: the standalone server's own implement execution over WebSocket never went through WorkbenchProcessScheduler at all, so ADR 0004's same-host mutation isolation was unenforced there. This PR closes that too — websocket.ts's implement path is now routed through WorkbenchRecoveryService.runMutating() (mutation lock + lease; no checkpoint capture yet, deliberately out of scope — see design.md Non-Goals).
  • Changeset applied: @openspec-ui/core 0.29.0→0.30.0, @openspec-ui/server 1.10.0→1.11.0, openspec-ui-vscode 0.26.0→0.27.0 (all minor).

Test plan

  • npm run typecheck workspace-wide
  • npm run lint (including lint:english) workspace-wide
  • npm run test workspace-wide — new workspace-lease.test.ts, extended process-scheduler.test.ts (lease-gated scheduling), new wire.test.ts, and a new real two-server-process WebSocket test in server.test.ts proving the lease actually blocks a competing host's implement attempt and unblocks after the first finishes
  • openspec change validate --strict cross-host-workspace-lease
  • [~] Manual smoke test with a real VS Code extension host: not performed (no interactive VS Code UI available in the environment this was built in) — the two-real-process WebSocket test is the closest available substitute, using the same file-based lease coordination a real second host would use. Flagged as still-open in tasks.md 7.3.

🤖 Generated with Claude Code

VeryComplexAndLongName and others added 2 commits August 28, 2026 10:36
ADR 0004's "one mutating run per workspace" invariant is enforced only
in-memory per process (WorkbenchProcessScheduler.mutationLocked,
WorkbenchRunJournal.writeQueue). Two hosts (VS Code extension + standalone
server, both legitimate per ADR 0001 decision 2) opened on the same
workspace can each believe they are the sole mutator, causing lost journal
updates. This adds ADR 0010 (advisory lease, v1: refuse-immediately, no
CAS/observer mode for now) plus the OpenSpec change proposal/design/tasks/
specs. Bundles the wire-contract COMMAND_KINDS duplication fix (wire.ts vs
protocol.ts) into the same change since it touches the same files.

No implementation yet — pausing here per plan for design review before
writing the lease/scheduler code itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
WorkbenchProcessScheduler's mutation lock and WorkbenchRunJournal's write
serialization are both private, per-process state. A VS Code extension
and a standalone server can legitimately be open on the same workspace
at once (ADR 0001 decision 2), each believing it is the sole mutator,
causing lost journal updates. Adds a versioned, file-based workspace
lease (write-then-rename, same pattern as the journal): a mutating run
acquires it, renews it while active, and releases it on completion; a
competing host is refused immediately with a message naming the current
holder, and a stale lease (crashed holder) is reclaimed and disclosed.

Also fixes wire.ts's COMMAND_KINDS duplicating core's CommandKind list
(same files this change already touches), and closes a larger
pre-existing gap found while implementing this: the standalone server's
own `implement` execution over WebSocket never went through the
scheduler at all, so ADR 0004's mutation isolation was unenforced there
even same-host. Both are now scheduler-gated the same way.

Adds workspace-lease.ts + tests, extends process-scheduler.ts (including
a fix so `completion` only resolves after lease release, not before,
per a real race the tests caught), wires the lease into
WorkbenchRecoveryService and the extension's activate(), and routes the
server's implement command through WorkbenchRecoveryService.runMutating()
(no checkpoint capture yet — mutation exclusivity only, a scoped-down
first pass; see design.md Non-Goals).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@VeryComplexAndLongName
VeryComplexAndLongName merged commit 94e8ff8 into main Aug 28, 2026
6 checks passed
VeryComplexAndLongName added a commit that referenced this pull request Aug 28, 2026
Merged in #99; task 7.3 (a fully manual VS Code + standalone smoke test)
stayed open (no interactive VS Code UI in that environment) but every
spec.md scenario has real test coverage, satisfying the archive gate in
openspec/config.yaml.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
@VeryComplexAndLongName
VeryComplexAndLongName deleted the feat/cross-host-workspace-lease branch August 31, 2026 06:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant